package com.imooc.bilibili.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imooc.bilibili.auth.UserAuthService;
import com.imooc.bilibili.constant.user.UserConstant;
import com.imooc.bilibili.domain.user.RefreshToken;
import com.imooc.bilibili.domain.user.UserInfo;
import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.mapper.user.UserInfoMapper;
import com.imooc.bilibili.mapper.user.UserMapper;
import com.imooc.bilibili.domain.user.User;
import com.imooc.bilibili.user.service.IRefreshTokenService;
import com.imooc.bilibili.user.service.UserService;
import com.imooc.bilibili.util.MD5Util;
import com.imooc.bilibili.util.RSAUtil;
import com.imooc.bilibili.util.StringUtils;
import com.imooc.bilibili.util.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author gcq
 * @Create 2022-05-21
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private UserAuthService authService;
    @Autowired
    private IRefreshTokenService tokenService;

    @Override
    public List<User> getUserAll() {
        return userMapper.selectList(null);
    }

    @Override
    public void addUser(User user) {
        String phone = user.getPhone();
        if(StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号不能为空");
        }

        User dbUser = getUserByPhone(phone);
        if(null != dbUser) {
            throw new ConditionException("该手机号已经注册!");
        }

        Date now = new Date();
        String salt = String.valueOf(now.getTime());
        String password = user.getPassword();
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败");
        }
        String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        user.setSalt(salt);
        user.setCreateTime(now);
        user.setPassword(md5Password);
        userMapper.insert(user);

        // 添加用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick(UserConstant.DEFAULT_NICK);
        userInfo.setBirth(UserConstant.DEFAULT_BIRTH);
        userInfo.setGender(UserConstant.GENDER_FEMALE);
        userInfo.setCreateTime(now);
        userInfoMapper.insert(userInfo);
        // 添加用户默认权限角色
        authService.addUserDefaultRole(user.getId());
    }

    @Override
    public String login(User user) throws Exception {
        String phone = user.getPhone();
        if(StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号不能为空");
        }

        User dbUser = getUserByPhone(phone);
        if(null == dbUser) {
            throw new ConditionException("当前用户不存在!");
        }

        String password = user.getPassword();
        String rawPassword = null;
        try {
            // 解密
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            e.printStackTrace();
        }

        String salt = dbUser.getSalt();
        String MD5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        if(!MD5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("密码错误");
        }

        return TokenUtil.generateToken(dbUser.getId());}

    @Override
    public User getUserInfo(Long currentUserId) {
        User user = userMapper.selectById(currentUserId);
        UserInfo userInfo = userInfoMapper.selectOne(new QueryWrapper<UserInfo>().eq("userId", currentUserId));
        user.setUserInfo(userInfo);
        return user;
    }

    @Override
    public void updateUserInfos(UserInfo userInfo) {
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("userId",userInfo.getUserId());
        updateWrapper.set("updateTime", new Date());
        userInfoMapper.update(userInfo, updateWrapper);
    }

    @Override
    public List<UserInfo> getUserInfoByUserIds(Set<Long> userIds) {
        return userMapper.getUserInfoByUserIds(userIds);
    }

    @Override
    public Page<UserInfo> pageListUserInfos(JSONObject params) {
        Integer no = params.getInteger("no");
        Integer size = params.getInteger("size");

        Page<UserInfo> page = new Page<>(((long) (no - 1) * size), size);
        return userInfoMapper.selectPage(page,
                new QueryWrapper<UserInfo>().like("nick", params.getString("nick")).orderByDesc("id"));
    }

    @Override
    public Map<String, Object> loginForDts(User user) throws Exception {
        String phone = user.getPhone();
        if(StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号不能为空");
        }

        User dbUser = getUserByPhone(phone);
        if(null == dbUser) {
            throw new ConditionException("当前用户不存在!");
        }

        String password = user.getPassword();
        String rawPassword = null;
        try {
            // 解密
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            e.printStackTrace();
        }

        String salt = dbUser.getSalt();
        String MD5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        if(!MD5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("密码错误");
        }

        Long userId = dbUser.getId();
        String accessToken = TokenUtil.generateToken(userId);
        String refreshToken = TokenUtil.generateRefreshToken(userId);

        tokenService.remove(new QueryWrapper<RefreshToken>().eq("refreshToken", refreshToken).eq("userId", userId));
        // 保存 refreshToken到数据库
        saveRefreshToken(userId, refreshToken);

        return returnToken(accessToken, refreshToken);
    }

    private Map<String, Object> returnToken(String accessToken, String refreshToken) {
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        return result;
    }

    private void saveRefreshToken(Long userId, String refreshToken) {
        RefreshToken token = new RefreshToken();
        token.setCreateTime(new Date());
        token.setUserId(userId);
        token.setRefreshToken(refreshToken);
        tokenService.save(token);
    }

    private User getUserByPhone(String phone) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        return userMapper.selectOne(queryWrapper);
    }
}